package middleware.optimize;

import middleware.llvm.BasicBlock;
import middleware.llvm.Module;
import middleware.llvm.enums.BinaryOpType;
import middleware.llvm.instruction.BinaryInstruction;
import middleware.llvm.instruction.Instruction;
import middleware.llvm.value.FunctionIRType;
import middleware.llvm.value.ImmediateValue;

/**
 * 窥孔优化
 * @author 杨凯伟
 */
public class PeepHole {
    private final Module irModule;

    public PeepHole(Module irModule) {
        this.irModule = irModule;
    }

    public Module pass() {
        irModule.getFunctions().forEach(this::passFunc);
        return irModule;
    }

    private void passFunc(FunctionIRType func) {
        func.getBasicBlocks().forEach(this::passBlock);
    }

    private void passBlock(BasicBlock block) {
        var instructions = block.getInstructions();
        for (Instruction inst : instructions) {
            if (inst instanceof BinaryInstruction binst) {
                if (binst.getOp() == BinaryOpType.ADD || binst.getOp() == BinaryOpType.SUB) {
                    if (binst.getOp() != BinaryOpType.SUB && binst.getLeft() instanceof ImmediateValue ileft && ileft.getValue() == 0) { // 0 + x
                        inst.replaceAllUseWith(binst.getRight(), false);
                    } else if (binst.getRight() instanceof ImmediateValue iright && iright.getValue() == 0) { // x + 0 or x - 0
                        inst.replaceAllUseWith(binst.getLeft(), false);
                    }
                } else if (binst.getOp() == BinaryOpType.MUL || binst.getOp() == BinaryOpType.SDIV) {
                    if (binst.getOp() != BinaryOpType.SDIV && binst.getLeft() instanceof ImmediateValue ileft && ileft.getValue() == 1) { // 1 * x
                        inst.replaceAllUseWith(binst.getRight(), false);
                    } else if (binst.getRight() instanceof ImmediateValue iright && iright.getValue() == 1) { // x * 1 or x / 1
                        inst.replaceAllUseWith(binst.getLeft(), false);
                    }
                }
            }
        }
    }
}
